Shader "Custom/Parallax"
{
	Properties
    {
        _RectSize ("RectSize", Range(0,10)) = 5
		_Depth ("Depth", Range(0,5)) = 1
    }
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 200

		Pass
		{
			Name "FORWARD"
			Tags { "LightMode" = "ForwardBase" }

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fwdbase
			#define PI 3.1415926
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"

			struct v2f
			{
				float4 pos : SV_POSITION;
				float4 worldPos: TEXCOORD1;
				SHADOW_COORDS(2)
			};

			v2f vert (appdata_full v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos (v.vertex);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				TRANSFER_SHADOW(o);
				return o;
			}

			half _RectSize;
			half _Depth;

			fixed positionInHole(float2 position){
				float x = abs(position.x);
				float y = abs(position.y);

				if(x < _RectSize && y < _RectSize){
					return 1;
				};
				return 0;
			}

			fixed4 frag (v2f IN) : SV_Target
			{
				float rotationAngle = fmod(_Time.x, 1.0f) * 2 * PI;

				float3x3 worldToHole = float3x3(
					cos(rotationAngle),	0,	sin(rotationAngle), 
					0,					1,	0,				 
					-sin(rotationAngle),0,	cos(rotationAngle));
				float3x3 holeToWorld = transpose(worldToHole);

				// transform world space to hole space and do calculation
				float3 holeSpacePosition = mul(worldToHole, IN.worldPos.xyz);

				// shading variable initialize
				fixed4 baseColor = fixed4(1,1,1,1);
				fixed atten = 1;

				// view and light
				half3 viewDir = mul(worldToHole, normalize(WorldSpaceViewDir(IN.worldPos)));
				// direction light, so we ignore worldpos input
				half3 lightDir = mul(worldToHole, UnityWorldSpaceLightDir(0));

				float pixelInHole = positionInHole(holeSpacePosition.xz);
				if(pixelInHole){
					float xMaxHitHeight = (_RectSize - holeSpacePosition.x) * viewDir.y / viewDir.x;
					float xMinHitHeight = (-_RectSize - holeSpacePosition.x) * viewDir.y / viewDir.x;
					float zMaxHitHeight = (_RectSize - holeSpacePosition.z) * viewDir.y / viewDir.z;
					float zMinHitHeight = (-_RectSize -holeSpacePosition.z) * viewDir.y / viewDir.z;

					half3 viewMarchingInVector = viewDir * _Depth / viewDir.y;
					float3 bottomIntersection = -viewMarchingInVector + holeSpacePosition;

					fixed isBottom = positionInHole(bottomIntersection.xz);
					float depth = 0;

					if(isBottom){
						baseColor = fixed4(0.5,1,1,1);
						holeSpacePosition = bottomIntersection;
						depth = -_Depth;
					}else{
						float xMin = min(xMinHitHeight, xMaxHitHeight);
						float zMin = min(zMaxHitHeight, zMinHitHeight);
						if(zMin < xMin){
							if(xMinHitHeight < xMaxHitHeight){
								// x = -_RectSize side
								baseColor = fixed4(1, 0, 0.5, 1);
								holeSpacePosition = float3(
									-_RectSize, 
									holeSpacePosition.y + xMinHitHeight, 
									holeSpacePosition.z + xMinHitHeight * viewDir.z / viewDir.y);
								depth = xMinHitHeight;
							}else{
								// x = _RectSize side
								baseColor = fixed4(0,1,0.5,1);
								holeSpacePosition = float3(
									_RectSize, 
									holeSpacePosition.y + xMaxHitHeight, 
									holeSpacePosition.z + xMaxHitHeight * viewDir.z / viewDir.y);
								depth = xMaxHitHeight;
							}
						}else{
							if(zMaxHitHeight < zMinHitHeight){
								// z = _RectSize side
								baseColor = fixed4(1,1,0.5,1);
								holeSpacePosition = float3(
									holeSpacePosition.x + zMaxHitHeight * viewDir.x / viewDir.y, 
									holeSpacePosition.y + zMaxHitHeight, 
									_RectSize);
								depth = zMaxHitHeight;
							}else{
								// z = -_RectSize side
								baseColor = fixed4(0,0, 0.5,1);
								holeSpacePosition = float3(
									holeSpacePosition.x + zMinHitHeight * viewDir.x / viewDir.y, 
									holeSpacePosition.y + zMinHitHeight, 
									-_RectSize);
								depth = zMinHitHeight;
							}
						}
					}

					// calculate self occulusion attenuation
					// marching to light direction and see planar intersection
					float3 lightMarchingOutVec = lightDir * (-depth) / lightDir.y;
					float3 occuPosition = lightMarchingOutVec + holeSpacePosition;
					float occuInHole = positionInHole(occuPosition.xz);
					if(!occuInHole){
						atten = 0;
					}
				};


				#if defined (SHADOWS_SCREEN)
					half4 coord = mul(unity_WorldToShadow[0], float4(mul(holeToWorld, holeSpacePosition), 1));
					atten = min(atten, unitySampleShadow(coord));
				#endif

				// hack to make it less dark
				atten = clamp(atten, 0.1, 1);

				return baseColor * atten;
			}

			ENDCG

		}
	}
}